package net.csdn.business.common.utils;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName RedisLockUtils
 * @Description zhangyl
 * @Author zhangyl
 * @Date 2024/2/29 11:50
 */
@Slf4j
@RequiredArgsConstructor
public class RedisLockUtils {

    public static final String LOCK = "lock:";

    private final RedisTemplate redisTemplate;

    /**
     * redis 自旋 阻塞锁
     *
     * @param lockName           锁的key
     * @param lockTimeOutSecond  锁的超时时间(单位:秒)
     * @param retryMilliSecond   重新获取锁，重试时间(单位:毫秒)
     * @param retryMaxTimeSecond 阻塞最大时间(单位:毫秒)
     * @return 不是null 说明锁定成功，是null 说明锁定失败
     */
    public String lockSynchronized(String lockName, int lockTimeOutSecond, int retryMilliSecond, int retryMaxTimeSecond) {
        long startTimeMillis = System.currentTimeMillis();
        while (true) {
            String lock = this.lock(lockName, lockTimeOutSecond);
            log.info("检查锁:{}，结果:{}", lockName, lock);
            if (StringUtils.isNotBlank(lock)) {
                return lock;
            }
            long currentTimeMillis = System.currentTimeMillis();
            if (currentTimeMillis - startTimeMillis > (retryMaxTimeSecond)) {
                //超过阻塞最大时间,锁定失败
                return null;
            }

            try {
                Thread.sleep(retryMilliSecond);
            } catch (InterruptedException e) {
                log.error("系统睡眠时间异常：", e);
                Thread.currentThread().interrupt();
            }
        }
    }

    /**
     * 释放锁
     *
     * @param lockName   锁的key
     * @param identifier 释放锁的标识
     * @return true:释放成功,false:释放失败
     */
    public boolean unlock(String lockName, String identifier) {
        if (StringUtils.isBlank(lockName) || StringUtils.isBlank(identifier)) {
            return false;
        }
        String lockKey = LOCK + lockName;
        String lockIdentifier = this.get(lockKey);
        if (identifier.equals(lockIdentifier)) {
            redisTemplate.delete(lockKey);
            return true;
        }
        return false;
    }

    /**
     * 加锁
     *
     * @param lockName 锁的key
     * @param seconds  锁的超时时间
     * @return 锁标识
     */
    public String lock(String lockName, int seconds) {
        if (StringUtils.isBlank(lockName)) {
            return null;
        }
        // 随机生成一个value
        String identifier = UUID.randomUUID().toString();
        // 锁名，即key值
        String lockKey = LOCK + lockName;
        // 超时时间，上锁后超过此时间则自动释放锁
        // 获取锁的超时时间，超过这个时间则放弃获取锁
        Boolean flag = redisTemplate.opsForValue().setIfAbsent(lockKey, identifier, seconds, TimeUnit.SECONDS);
        if (flag != null && flag) {
            return identifier;
        }
        return null;
    }

    /**
     * 获取redis 的值
     */
    private String get(String key) {
        Object object = redisTemplate.opsForValue().get(key);
        if (object == null) {
            return null;
        }
        return (String) object;
    }
    public boolean setEx(String key, int seconds){

        return redisTemplate.expire(key,seconds,TimeUnit.SECONDS);
    }

    /**
     * 更新key的
     */
    public boolean setEx(List<String> keys,String value, int seconds) {
        boolean result=false;
        if(keys!=null&&keys.size()>0&&value!=null){
            for (String key:keys){
                Object object = redisTemplate.opsForValue().get(key);
                //证明还没过期，则更新过期时间
                if (object != null&&value.equals((String)object)) {
                    result=redisTemplate.expire(key,seconds,TimeUnit.SECONDS);
                }
            }
        }
        return result;
    }

}
